/*
 * SIT_DateTime.c : drop down list with user editable text area.
 *
 * Written by T.Pierron, Dec 7, 2008.
 */

#include "SIT_P.h"
#include <stdio.h>
#include <malloc.h>

	TagList DateTimeClass[] = {
		{ SIT_SuperClass,    NULL,            ___, SIT_INT, (ULONG) WidgetClass },
		{ SIT_DateFormat,    "dateFormat",    _SG, SIT_INT, OFFSET(SIT_DateTime, sd_DateFormat) },
		{ SIT_CurrentDate,   "currentDate",   _SG, SIT_PTR, OFFSET(SIT_DateTime, sd_CurDate) },
		{ SIT_CustomTimeFmt, "customTimeFmt", _SG, SIT_STR, OFFSET(SIT_DateTime, sd_DateTimeFmt) },
		{ SIT_TagEnd }
	};

static int SIT_MeasureDateTime(SIT_Widget w, APTR cd, APTR ud)
{
	/* DTM_GETIDEALSIZE is Vista or better only :-( */
	HDC     hdc = GetDC(w->sw_Handle);
	HGDIOBJ old = SelectObject(hdc, w->sw_Font);
	LPWSTR  hms = L"99:99:99 AM";
	SIZE *  ret = cd;

	GetTextExtentPoint32(hdc, hms, wcslen(hms), ret);
	ret->cx += 10 + GetSystemMetrics(SM_CYHSCROLL);
	ret->cy += 6;
	SelectObject(hdc, old);
	if (((SIT_DateTime)w)->sd_DateFormat != SITV_TimeOnly && ret->cx < 150)
		ret->cx = 150;
	ReleaseDC(w->sw_Handle, hdc);
	return 0;
}

/* Sync control with date stored in sd_CurDate */
static void SIT_SetCurrentDate(SIT_DateTime date)
{
	SYSTEMTIME  sys;
	struct tm * tm = &date->sd_CurDate;

	sys.wYear      = tm->tm_year + 1900;
	sys.wMonth     = tm->tm_mon + 1;
	sys.wDay       = tm->tm_mday;
	sys.wDayOfWeek = tm->tm_wday;
	sys.wHour      = tm->tm_hour;
	sys.wMinute    = tm->tm_min;
	sys.wSecond    = tm->tm_sec;
	sys.wMilliseconds = 0;

	DateTime_SetSystemtime(date->super.sw_Handle, GDT_VALID, &sys);
}

void SIT_SyncDate(SIT_Widget w, LPSYSTEMTIME sys)
{
	struct tm * tm = &((SIT_DateTime)w)->sd_CurDate;

	tm->tm_year = sys->wYear - 1900;
	tm->tm_mon  = sys->wMonth - 1;
	tm->tm_mday = sys->wDay;
	tm->tm_wday = sys->wDayOfWeek;
	tm->tm_hour = sys->wHour;
	tm->tm_min  = sys->wMinute;
	tm->tm_sec  = sys->wSecond;
}

/* Change date format according string specified */
static void SIT_SetDateFormat(SIT_DateTime date)
{
	LPWSTR utf16;

	UTF8ToUTF16(date->sd_DateTimeFmt, utf16);

	DateTime_SetFormat(date->super.sw_Handle, utf16);
}

static int SIT_SetDateTimeValues(SIT_Widget w, APTR cd, APTR ud)
{
	TagList *     tag   = cd;
	SIT_Variant * value = ud;
	SIT_DateTime  date  = (SIT_DateTime) w;
	int           style;

	switch (tag->tl_TagID) {
	case SIT_DateFormat:
		date->sd_DateFormat = value->integer;
		if (w->sw_Handle)
		{
			style = GetWindowStyle(w->sw_Handle) & ~(DTS_LONGDATEFORMAT |
				DTS_SHORTDATEFORMAT | DTS_TIMEFORMAT);

			switch (date->sd_DateFormat) {
			case SITV_DateShort: style |= DTS_SHORTDATEFORMAT; break;
			case SITV_DateLong:  style |= DTS_LONGDATEFORMAT; break;
			case SITV_TimeOnly:  style |= DTS_TIMEFORMAT;
			}
			SetWindowLong(w->sw_Handle, GWL_STYLE, style);
		}
		break;
	case SIT_CurrentDate:
		memcpy(&date->sd_CurDate, value->pointer, sizeof (struct tm));
		if (w->sw_Handle) SIT_SetCurrentDate(date);
		else date->sd_SetDate = True;
		break;
	case SIT_CustomTimeFmt:
		SIT_SetWidgetValue(&date->super, cd, ud);
		if (w->sw_Handle) SIT_SetDateFormat(date);
	}
	return 0;
}

BOOL SIT_CreateDateTime(SIT_Widget w, va_list args)
{
	SIT_DateTime date  = (SIT_DateTime) w;
	int          style = WS_CHILD | WS_VISIBLE;
	HWND         hwnd;

	/* Default values */
	w->sw_SetValue = SIT_SetDateTimeValues;
	w->sw_OptimalWidth = SIT_MeasureDateTime;

	SIT_ParseTags(w, args, w->sw_Class = DateTimeClass);

	switch (date->sd_DateFormat) {
	case SITV_DateShort: style |= DTS_SHORTDATEFORMAT; break;
	case SITV_DateLong:  style |= DTS_LONGDATEFORMAT; break;
	case SITV_TimeOnly:  style |= DTS_TIMEFORMAT;
	}
	if (HAS_TAB(w)) style |= WS_TABSTOP;

	hwnd = w->sw_Handle = CreateWindowEx(0, DATETIMEPICK_CLASS, w->sw_Name,
		style, 0, 0, 10, 10, SIT_GetContainer(w), (HMENU) MAKE_ID(w), instance, NULL);

	if (hwnd == NULL) return FALSE;
	SIT_SetDefaultFont(w);

	if (date->sd_SetDate) SIT_SetCurrentDate(date);
	if (IsDef(date->sd_DateTimeFmt)) SIT_SetDateFormat(date);

	SYSTEMTIME sys;
	DateTime_GetSystemtime(hwnd, &sys);
	SIT_SyncDate(w, &sys);

	SetProp(hwnd, sit_class, (HANDLE) w);

	return TRUE;
}
